// Refactored by Fredrique Samuels (fredriquesamuels@gmail.com)

#ifndef SIGSLOT0_H__
#define SIGSLOT0_H__

#include "base.h"

namespace sigslot {

//========================================

template<class mt_policy> class _connection_base0 :
	public connection_interface {
public:
	virtual has_slots<mt_policy>* getdest()=0;

};

//========================================

template<class dest_type, class mt_policy> class _connection0 :
	public _connection_base0<mt_policy> {
public:
	_connection0(dest_type* pobject, void (dest_type::*pmemfun)()) {
		m_pobject = pobject;
		m_pmemfun = pmemfun;
	}

	inline virtual void emit() {
		(((dest_type*)getdest())->*m_pmemfun)();
	}

	inline virtual has_slots<mt_policy>* getdest() {
		return m_pobject;
	}

private:
	dest_type* m_pobject;
	void (dest_type::*m_pmemfun)();
};

template<class mt_policy>
class _signal_base0 :public _signal_base<mt_policy> {
public:

	_signal_base0() {

	}

	virtual ~_signal_base0() {

	}

	virtual void disconnect(has_slots<mt_policy>* pclass)=0;
};

template<class mt_policy=SIGSLOT_DEFAULT_MT_POLICY>
class signal0:public _signal_base0<mt_policy> {
public:

	typedef std::list<connection_interface* > connections_list;

	signal0() :_signal_base0<mt_policy>() {

	}

	virtual ~signal0() {
		disconnect_all();
	}

	template<class desttype>
	inline void connect(desttype* pclass, void (desttype::*pmemfun)())
	{
		lock_block<mt_policy> lock(this);
		_connection0<desttype,mt_policy>* conn =
		new _connection0<desttype,mt_policy>(pclass, pmemfun);
		m_connected_slots.push_back(conn);
		pclass->signal_connect(this);

	}

	inline void emit()
	{
		lock_block<mt_policy> lock(this);
		connections_list::const_iterator itNext, it = m_connected_slots.begin();
		connections_list::const_iterator itEnd = m_connected_slots.end();
	
		while(it != itEnd)
		{
			itNext = it;
			++itNext;

			conn_emit(((_connection_base0<mt_policy>*)(*it))->getdest(),(*it));
			it = itNext;
		}
	}
	
	inline void disconnect(has_slots<mt_policy>* pclass)
	{
		lock_block<mt_policy> lock(this);
		connections_list::iterator it = m_connected_slots.begin();
		connections_list::iterator itEnd = m_connected_slots.end();

		while(it != itEnd)
		{
			if(((_connection_base0<mt_policy>*)(*it))->getdest() == pclass)
			{
				delete *it;
				m_connected_slots.erase(it);
				pclass->signal_disconnect(this);
				return;
			}

			++it;
		}
	}

	inline void disconnect_all()
	{
		lock_block<mt_policy> lock(this);
		connections_list::const_iterator it = m_connected_slots.begin();
		connections_list::const_iterator itEnd = m_connected_slots.end();

		while(it != itEnd)
		{
			((_connection_base0<mt_policy>*)(*it))->getdest()->signal_disconnect(this);
			delete *it;

			++it;
		}

		m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
	}
	
protected:
	template<class desttype>
	void conn_emit(desttype* pclass,void* conn){
		((_connection0<desttype,mt_policy>*)conn)->emit();
	}
		
	connections_list m_connected_slots;

};

}// namespace sigslot

#endif // SIGSLOT_H__
